package com.ruoyi.system.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import com.ruoyi.common.annotation.UserDataIsolation;
import com.ruoyi.common.enums.NotificationMethod;
import com.ruoyi.common.enums.Severity;
import com.ruoyi.system.domain.AlarmReceiver;
import com.ruoyi.system.domain.MonitorRule;
import com.ruoyi.system.domain.ProjectAlarmRule;
import com.ruoyi.system.domain.ProjectAuthorize;
import com.ruoyi.system.domain.vo.QueryVo;
import com.ruoyi.system.mapper.ProjectAlarmRuleMapper;
import com.ruoyi.system.service.IAlarmReceiverService;
import com.ruoyi.system.service.IMonitorRuleService;
import com.ruoyi.system.service.IProjectAlarmRuleService;
import com.ruoyi.system.service.IProjectAuthorizeService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class ProjectAlarmRuleServiceImpl implements IProjectAlarmRuleService
{
    @Autowired
    ProjectAlarmRuleMapper projectAlarmRuleMapper;

    @Autowired
    IMonitorRuleService monitorRuleService;

    @Autowired
    IProjectAuthorizeService projectAuthorizeService;

    @Autowired
    IAlarmReceiverService alarmReceiverService;

    @Override
    @UserDataIsolation(tableAlias = "tbl_project_alarm_rule")
    public Map<String, Object> findExistance(ProjectAlarmRule projectAlarmRule) {
        return projectAlarmRuleMapper.findExistance(projectAlarmRule);
    }

    private void setReceivers(ProjectAlarmRule projectAlarmRule) {
        ProjectAuthorize queryDTO = new ProjectAuthorize();
        queryDTO.setProjectId(projectAlarmRule.getProjectId());
        List<ProjectAuthorize> projectAuthorizes = projectAuthorizeService.queryAuthorizeUserInfo(queryDTO);
        Set<Integer> validUserIds = new TreeSet<>();
        for (ProjectAuthorize projectAuthorize : projectAuthorizes) {
            validUserIds.add(projectAuthorize.getUserId());
        }
        List<AlarmReceiver> receivers = new ArrayList<>();
        for (Integer userId : projectAlarmRule.getSmsReceivers()) {
            try {
                if (!validUserIds.contains(userId)) {
                    continue;
                }
                AlarmReceiver receiver = new AlarmReceiver();
                receiver.setRuleId(projectAlarmRule.getId());
                receiver.setMethod(NotificationMethod.SMS.getCode());
                receiver.setUserId(userId);
                receiver.setCompanyId(projectAlarmRule.getCompanyId());
                receivers.add(receiver);
            } catch(Exception e) {
                log.info("",e);
                StackTraceElement[] traces = e.getStackTrace();
                for (StackTraceElement trace : traces) {
                    log.debug(trace.toString());
                }
            }
        }
        for (Integer userId : projectAlarmRule.getMailReceivers()) {
            try {
                if (!validUserIds.contains(userId)) {
                    continue;
                }
                AlarmReceiver receiver = new AlarmReceiver();
                receiver.setRuleId(projectAlarmRule.getId());
                receiver.setMethod(NotificationMethod.EMAIL.getCode());
                receiver.setUserId(userId);
                receiver.setCompanyId(projectAlarmRule.getCompanyId());
                receivers.add(receiver);
            } catch(Exception e) {
                log.info("",e);
                StackTraceElement[] traces = e.getStackTrace();
                for (StackTraceElement trace : traces) {
                    log.debug(trace.toString());
                }
            }
        }
        for (Integer userId : projectAlarmRule.getVoiceReceivers()) {
            try {
                if (!validUserIds.contains(userId)) {
                    continue;
                }
                AlarmReceiver receiver = new AlarmReceiver();
                receiver.setRuleId(projectAlarmRule.getId());
                receiver.setMethod(NotificationMethod.VOICE.getCode());
                receiver.setUserId(userId);
                receiver.setCompanyId(projectAlarmRule.getCompanyId());
                receivers.add(receiver);
            } catch(Exception e) {
                log.info("",e);
                StackTraceElement[] traces = e.getStackTrace();
                for (StackTraceElement trace : traces) {
                    log.debug(trace.toString());
                }
            }
        }
        for (Integer userId : projectAlarmRule.getWechatReceivers()) {
            try {
                if (!validUserIds.contains(userId)) {
                    continue;
                }
                AlarmReceiver receiver = new AlarmReceiver();
                receiver.setRuleId(projectAlarmRule.getId());
                receiver.setMethod(NotificationMethod.WECHAT.getCode());
                receiver.setUserId(userId);
                receiver.setCompanyId(projectAlarmRule.getCompanyId());
                receivers.add(receiver);
            } catch(Exception e) {
                log.info("",e);
                StackTraceElement[] traces = e.getStackTrace();
                for (StackTraceElement trace : traces) {
                    log.debug(trace.toString());
                }
            }
        }
        if (!receivers.isEmpty()) {
            QueryVo queryVo = new QueryVo();
            queryVo.filters.put("rule_id", projectAlarmRule.getId());
            clearReceivers(queryVo);
            alarmReceiverService.set(receivers);
        }
    }

    private void clearReceivers(QueryVo queryVo) {
        alarmReceiverService.clear(queryVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer create(ProjectAlarmRule projectAlarmRule) {
        Integer id = null;
        try {
            Integer affected = projectAlarmRuleMapper.create(projectAlarmRule);
            if (affected > 0) {
                id = projectAlarmRule.getId();
            }
            setReceivers(projectAlarmRule);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.info("",e);
            StackTraceElement[] traces = e.getStackTrace();
            for (StackTraceElement trace : traces) {
                log.debug(trace.toString());
            }
        }
        return id;
    }

    @Override
    @UserDataIsolation(tableAlias = "par")
    public List<ProjectAlarmRule> index(QueryVo queryVo) {
        List<ProjectAlarmRule> projectAlarmRules = projectAlarmRuleMapper.index(queryVo);
        for (ProjectAlarmRule projectAlarmRule : projectAlarmRules) {
            QueryVo subQueryVo = new QueryVo();
            subQueryVo.filters.put("rule_id", projectAlarmRule.getId());
            List<Map<String, Object>> receivers = alarmReceiverService.get(subQueryVo);
            log.info("{}", receivers);
            List<Integer> smsReceivers = new ArrayList<>();
            List<Integer> mailReceivers = new ArrayList<>();
            List<Integer> voiceReceivers = new ArrayList<>();
            List<Integer> wechatReceivers = new ArrayList<>();
            for (Map<String, Object> receiver : receivers) {
                Long method = (Long)receiver.get("method");
                Integer chosen = Integer.parseInt(receiver.get("chosen").toString());
                if (chosen == 0) {
                    continue;
                }
                if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.SMS)) {
                    smsReceivers.add(((Long)receiver.get("user_id")).intValue());
                } else if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.EMAIL)) {
                    mailReceivers.add(((Long)receiver.get("user_id")).intValue());
                } else if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.VOICE)) {
                    voiceReceivers.add(((Long)receiver.get("user_id")).intValue());
                } else if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.WECHAT)) {
                    wechatReceivers.add(((Long)receiver.get("user_id")).intValue());
                }
            }
            projectAlarmRule.setSmsReceivers(smsReceivers);
            projectAlarmRule.setMailReceivers(mailReceivers);
            projectAlarmRule.setVoiceReceivers(voiceReceivers);
            projectAlarmRule.setWechatReceivers(wechatReceivers);
            projectAlarmRule.setSeverityString(Severity.valueOfCode(projectAlarmRule.getSeverity()).getLabel());
        }
        return projectAlarmRules;
    }

    @Override
    @UserDataIsolation(tableAlias = "mr")
    public List<Map<String, Object>> available(QueryVo queryVo) {
        List<Map<String, Object>> monitorRules = projectAlarmRuleMapper.available(queryVo);
        return monitorRules;
    }

    @Override
    @UserDataIsolation(tableAlias = "tbl_project_alarm_rule")
    public ProjectAlarmRule retrieve(QueryVo queryVo) {
        ProjectAlarmRule projectAlarmRule = projectAlarmRuleMapper.retrieve(queryVo);
        if (projectAlarmRule != null) {
            projectAlarmRule.setSeverityString(Severity.valueOfCode(projectAlarmRule.getSeverity()).getLabel());
            QueryVo subQueryVo = new QueryVo();
            subQueryVo.filters.put("rule_id", projectAlarmRule.getId());
            List<Map<String, Object>> receivers = alarmReceiverService.get(subQueryVo);
            log.info("{}", receivers);
            List<Integer> smsReceivers = new ArrayList<>();
            List<Integer> mailReceivers = new ArrayList<>();
            List<Integer> voiceReceivers = new ArrayList<>();
            List<Integer> wechatReceivers = new ArrayList<>();
            for (Map<String, Object> receiver : receivers) {
                Long method = (Long)receiver.get("method");
                Integer chosen = Integer.parseInt(receiver.get("chosen").toString());
                if (chosen == 0) {
                    continue;
                }
                if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.SMS)) {
                    smsReceivers.add(((Long)receiver.get("user_id")).intValue());
                } else if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.EMAIL)) {
                    mailReceivers.add(((Long)receiver.get("user_id")).intValue());
                } else if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.VOICE)) {
                    voiceReceivers.add(((Long)receiver.get("user_id")).intValue());
                } else if (NotificationMethod.valueOfCode(method.intValue()).equals(NotificationMethod.WECHAT)) {
                    wechatReceivers.add(((Long)receiver.get("user_id")).intValue());
                }
            }
            projectAlarmRule.setSmsReceivers(smsReceivers);
            projectAlarmRule.setMailReceivers(mailReceivers);
            projectAlarmRule.setVoiceReceivers(voiceReceivers);
            projectAlarmRule.setWechatReceivers(wechatReceivers);
            projectAlarmRule.setSeverityString(Severity.valueOfCode(projectAlarmRule.getSeverity()).getLabel());
            subQueryVo.filters.clear();
            subQueryVo.filters.put("id", projectAlarmRule.getMonitorRuleId());
            MonitorRule monitorRule = monitorRuleService.retrieve(subQueryVo);
            projectAlarmRule.setMonitorRule(monitorRule);
        }
        return projectAlarmRule;
    }

    @Override
    @UserDataIsolation(tableAlias = "tbl_project_alarm_rule")
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(ProjectAlarmRule projectAlarmRule) {
        Boolean done = false;
        try {
            Integer affected = projectAlarmRuleMapper.update(projectAlarmRule);
            if (affected > 0) {
                done = true;
            }
            setReceivers(projectAlarmRule);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.info("",e);
            StackTraceElement[] traces = e.getStackTrace();
            for (StackTraceElement trace : traces) {
                log.debug(trace.toString());
            }
        }
        return done;
    }

    @Override
    @UserDataIsolation(tableAlias = "tbl_project_alarm_rule")
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(QueryVo queryVo) {
        Boolean done = false;
        try {
            Integer affected = projectAlarmRuleMapper.delete(queryVo);
            if (affected > 0) {
                done = true;
            }
            QueryVo subQueryVo = new QueryVo();
            subQueryVo.filters.put("rule_id", queryVo.filters.getInteger("id"));
            clearReceivers(subQueryVo);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.info("",e);
            StackTraceElement[] traces = e.getStackTrace();
            for (StackTraceElement trace : traces) {
                log.debug(trace.toString());
            }
        }
        return done;
    }
}
